{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Wait for User Input"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "var userHomeDir = System.getProperty(\"user.home\");\n",
    "var localRespoUrl = \"file://\" + userHomeDir + \"/.m2/repository/\";\n",
    "var langchain4jVersion = \"1.0.1\";\n",
    "var langchain4jbeta = \"1.0.1-beta6\";\n",
    "var langgraph4jVersion = \"1.6-SNAPSHOT\";"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash \n",
    "rm -rf \\{userHomeDir}/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/bsc/langgraph4j"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%dependency /add-repo local \\{localRespoUrl} release|never snapshot|always\n",
    "// %dependency /list-repos\n",
    "%dependency /add org.bsc.langgraph4j:langgraph4j-core:\\{langgraph4jVersion}\n",
    "%dependency /add org.bsc.langgraph4j:langgraph4j-langchain4j:\\{langgraph4jVersion}\n",
    "%dependency /add dev.langchain4j:langchain4j:\\{langchain4jVersion}\n",
    "// %dependency /add dev.langchain4j:langchain4j-open-ai:\\{langchain4jVersion}\n",
    "%dependency /add dev.langchain4j:langchain4j-ollama:\\{langchain4jbeta}\n",
    "%dependency /add net.sourceforge.plantuml:plantuml-mit:1.2024.6\n",
    "%dependency /list-dependencies\n",
    "%dependency /resolve"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**utility to render graph respresentation in PlantUML**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import net.sourceforge.plantuml.SourceStringReader;\n",
    "import net.sourceforge.plantuml.FileFormatOption;\n",
    "import net.sourceforge.plantuml.FileFormat;\n",
    "import org.bsc.langgraph4j.GraphRepresentation;\n",
    "\n",
    "void displayDiagram( GraphRepresentation representation ) throws IOException { \n",
    "    \n",
    "    var reader = new SourceStringReader(representation.getContent());\n",
    "\n",
    "    try(var imageOutStream = new java.io.ByteArrayOutputStream()) {\n",
    "\n",
    "        var description = reader.outputImage( imageOutStream, 0, new FileFormatOption(FileFormat.PNG));\n",
    "\n",
    "        var imageInStream = new java.io.ByteArrayInputStream(  imageOutStream.toByteArray() );\n",
    "\n",
    "        var image = javax.imageio.ImageIO.read( imageInStream );\n",
    "\n",
    "        display(  image );\n",
    "\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define graph with interruption"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "SLF4J: No SLF4J providers were found.\n",
      "SLF4J: Defaulting to no-operation (NOP) logger implementation\n",
      "SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.\n"
     ]
    },
    {
     "data": {
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import org.bsc.langgraph4j.*;\n",
    "import org.bsc.langgraph4j.prebuilt.MessagesState;\n",
    "import org.bsc.langgraph4j.state.Channel;\n",
    "import dev.langchain4j.data.message.AiMessage;\n",
    "import dev.langchain4j.data.message.ChatMessage;\n",
    "import org.bsc.langgraph4j.action.AsyncNodeAction;\n",
    "import org.bsc.langgraph4j.action.AsyncEdgeAction;\n",
    "import static org.bsc.langgraph4j.action.AsyncNodeAction.node_async;\n",
    "import static org.bsc.langgraph4j.action.AsyncEdgeAction.edge_async;\n",
    "import org.bsc.langgraph4j.checkpoint.MemorySaver;\n",
    "import org.bsc.langgraph4j.CompileConfig;\n",
    "import static org.bsc.langgraph4j.StateGraph.END;\n",
    "import static org.bsc.langgraph4j.StateGraph.START;\n",
    "\n",
    "public class State extends MessagesState<String> {\n",
    "\n",
    "    public State(Map<String, Object> initData) {\n",
    "        super( initData  );\n",
    "    }\n",
    "\n",
    "    public Optional<String> humanFeedback() {\n",
    "        return value(\"human_feedback\");\n",
    "    }\n",
    "\n",
    "}\n",
    "\n",
    "AsyncNodeAction<State> step1 = node_async( state -> {\n",
    "    return Map.of( \"messages\", \"Step 1\" );\n",
    "});\n",
    "\n",
    "AsyncNodeAction<State> humanFeedback = node_async( state -> {\n",
    "    return Map.of();\n",
    "});\n",
    "\n",
    "AsyncNodeAction<State> step3 = node_async( state -> {\n",
    "    return Map.of( \"messages\", \"Step 3\" );\n",
    "});\n",
    "\n",
    "AsyncEdgeAction<State> evalHumanFeedback = edge_async( state -> {\n",
    "    var feedback = state.humanFeedback().orElseThrow();\n",
    "    return ( feedback.equals(\"next\") || feedback.equals(\"back\") ) ? feedback : \"unknown\";\n",
    "});\n",
    "\n",
    "var builder = new StateGraph<>(State.SCHEMA, State::new)\n",
    "    .addNode(\"step_1\", step1)\n",
    "    .addNode(\"human_feedback\", humanFeedback)\n",
    "    .addNode(\"step_3\", step3)\n",
    "    .addEdge(START, \"step_1\")\n",
    "    .addEdge(\"step_1\", \"human_feedback\")\n",
    "    .addConditionalEdges(\"human_feedback\", evalHumanFeedback, \n",
    "        Map.of( \"back\", \"step_1\", \"next\", \"step_3\", \"unknown\", \"human_feedback\" ))\n",
    "    .addEdge(\"step_3\", END)\n",
    "    ;\n",
    "\n",
    "// Set up memory\n",
    "var saver = new MemorySaver();\n",
    "\n",
    "// Add\n",
    "var compileConfig = CompileConfig.builder()\n",
    "                        .checkpointSaver(saver)\n",
    "                        .interruptBefore(\"human_feedback\")\n",
    "                        .releaseThread(true)\n",
    "                        .build();\n",
    "\n",
    "var graph = builder.compile(compileConfig);\n",
    "\n",
    "\n",
    "displayDiagram( graph.getGraph(GraphRepresentation.Type.PLANTUML, \"Human in the Loop\", false) );\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Start graph until interruption"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NodeOutput{node=__START__, state={messages=[Step 0]}}\n",
      "NodeOutput{node=step_1, state={messages=[Step 0, Step 1]}}\n"
     ]
    }
   ],
   "source": [
    "// Input\n",
    "Map<String,Object> initialInput = Map.of(\"messages\", \"Step 0\");\n",
    "\n",
    "// Thread\n",
    "var invokeConfig = RunnableConfig.builder()\n",
    "                        .threadId(\"Thread1\")\n",
    "                        .build();\n",
    "\n",
    "// Run the graph until the first interruption\n",
    "for (var event : graph.stream(initialInput, invokeConfig)) {\n",
    "    System.out.println(event);\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Wait for user input and update state\n",
    "\n",
    "⚠️ The Java notebook, until now, doesn't support user input (take a look [issue #39](https://github.com/padreati/rapaio-jupyter-kernel/issues/39)) so we could simulate input ⚠️"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--State before update--\n",
      "StateSnapshot{node=step_1, state={messages=[Step 0, Step 1]}, config=RunnableConfig{ threadId=Thread1, checkPointId=85b3831c-45b1-4e58-9016-c70bb130110b, nextNode=human_feedback, streamMode=VALUES }}\n",
      "\n",
      "--User Input--\n",
      "Tell me how you want to update the state: 'back'\n",
      "\n",
      "--State after update--\n",
      "StateSnapshot{node=step_1, state={messages=[Step 0, Step 1], human_feedback=back}, config=RunnableConfig{ threadId=Thread1, checkPointId=85b3831c-45b1-4e58-9016-c70bb130110b, nextNode=human_feedback, streamMode=VALUES }}\n",
      "\n",
      "getNext()\n",
      "\twith invokeConfig:[human_feedback]\n",
      "\twith updateConfig:[human_feedback]\n"
     ]
    }
   ],
   "source": [
    "\n",
    "// We can check the state\n",
    "System.out.printf(\"--State before update--\\n%s\\n\", graph.getState(invokeConfig));\n",
    "\n",
    "// Simulate user input\n",
    "var userInput = \"back\"; // back means we want to go back to the previous node\n",
    "System.out.printf(\"\\n--User Input--\\nTell me how you want to update the state: '%s'\\n\\n\", userInput);\n",
    "\n",
    "// We now update the state as if we are the human_feedback node\n",
    "var updateConfig = graph.updateState(invokeConfig, Map.of(\"human_feedback\", userInput), null);\n",
    "\n",
    "// We can check the state\n",
    "System.out.printf(\"--State after update--\\n%s\\n\", graph.getState(invokeConfig) );\n",
    "\n",
    "// We can check the next node, showing that it is node 3 (which follows human_feedback)\n",
    "System.out.printf(\"\\ngetNext()\\n\\twith invokeConfig:[%s]\\n\\twith updateConfig:[%s]\\n\", \n",
    "            graph.getState(invokeConfig).getNext(),  \n",
    "            graph.getState(updateConfig).getNext());\n",
    ";"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Continue graph execution after interruption"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NodeOutput{node=human_feedback, state={messages=[Step 0, Step 1], human_feedback=back}}\n",
      "NodeOutput{node=step_1, state={messages=[Step 0, Step 1], human_feedback=back}}\n"
     ]
    }
   ],
   "source": [
    "// Continue the graph execution\n",
    "for (var event : graph.stream(null, updateConfig)) {\n",
    "    System.out.println(event);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Waif for user input (again) and update state\n",
    "\n",
    "⚠️ The Java notebook, until now, doesn't support user input (take a look [issue #39](https://github.com/padreati/rapaio-jupyter-kernel/issues/39)) so we could simulate input ⚠️"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "--User Input--\n",
      "Tell me how you want to update the state: 'next'\n",
      "\n",
      "getNext()\n",
      "\twith invokeConfig:[human_feedback]\n",
      "\twith updateConfig:[human_feedback]\n"
     ]
    }
   ],
   "source": [
    "var userInput = \"next\"; // 'next' means we want to go to the next node\n",
    "System.out.printf(\"\\n--User Input--\\nTell me how you want to update the state: '%s'\\n\", userInput);\n",
    "\n",
    "// We now update the state as if we are the human_feedback node\n",
    "var updateConfig = graph.updateState(invokeConfig, Map.of(\"human_feedback\", userInput), null);\n",
    "\n",
    "System.out.printf(\"\\ngetNext()\\n\\twith invokeConfig:[%s]\\n\\twith updateConfig:[%s]\\n\", \n",
    "            graph.getState(invokeConfig).getNext(),  \n",
    "            graph.getState(updateConfig).getNext());\n",
    "            ;   \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Continue graph execution after the 2nd interruption"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NodeOutput{node=human_feedback, state={messages=[Step 0, Step 1], human_feedback=next}}\n",
      "NodeOutput{node=step_3, state={messages=[Step 0, Step 1, Step 3], human_feedback=next}}\n",
      "NodeOutput{node=__END__, state={messages=[Step 0, Step 1, Step 3], human_feedback=next}}\n"
     ]
    }
   ],
   "source": [
    "// Continue the graph execution\n",
    "for (var event : graph.stream(null, updateConfig)) {\n",
    "    System.out.println(event);\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Java (rjk 2.2.0)",
   "language": "java",
   "name": "rapaio-jupyter-kernel"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "java",
   "nbconvert_exporter": "script",
   "pygments_lexer": "java",
   "version": "22.0.2+9-70"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
